package com.yanxu.impl;

import com.yanxu.IFileCopy;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @author 折戟沉沙铁未销
 * @version V1.0
 * @date 2025-05-30-2025
 * @Description: 使用 nio 进行文件拷贝
 */
@SuppressWarnings("all")
public class NioFileCopy {
    public static void main(String[] args) throws IOException {
        NioFileCopy nioFileCopy = new NioFileCopy();
        //nioFileCopy.copyFile_Nio();
        nioFileCopy.copyFile_transferto();
    }

    /* 使用 nio Channel、ByteBuffer 进行文件拷贝*/
    public void copyFile_Nio() throws IOException {
        IFileCopy fileCopy = new IFileCopy() {
            @Override
            public void copyFile(File source, File target) throws IOException {
                FileChannel fin = null;
                FileChannel fout = null;
                try {
                    fin = new FileInputStream(source).getChannel();
                    fout = new FileOutputStream(target).getChannel();

                    // 定义 bytebuffer
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

                    // 从 源文件通道FileChannel中读取，写入到 bytebuffer 中去
                    // 对 channel 进行的是读操作，对 byteBuffer 是写操作。
                    while (fin.read(byteBuffer) != -1) {
                        // 翻转。 从 bytebuffer 由 【写模式】 切换到 【读模式】。
                        // 需要从 bytebuffer 中读取数据。
                        byteBuffer.flip();

                        // 直接 fout.write(byteBuffer); 这样写入到channel, 不靠谱。该方法并不能保证将 byteBuffer 中的数据全部一次写完。
                        // fout.write(byteBuffer);
                        // 在一个循环中，将 bytebuffer 中的数据写入到 fileChannel 中
                        while (byteBuffer.hasRemaining()) {
                            fout.write(byteBuffer);
                        }

                        // 压缩
                        byteBuffer.compact();

                        // 清空 （调用这个方法也是可以的）
                        //byteBuffer.clear();
                    }
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } finally {
                    if (fin != null) {
                        fin.close();
                    }
                    if (fout != null) {
                        fout.close();
                    }
                }
            }
        };
        fileCopy.copyFile(new File("F:\\1111.zip"), new File("F:\\11114.zip"));
    }

    /* 使用 nio transferto 进行文件拷贝*/
    public void copyFile_transferto() throws IOException {
        IFileCopy fileCopy = new IFileCopy() {
            @Override
            public void copyFile(File source, File target) throws IOException {
                FileChannel fin = null;
                FileChannel fout = null;
                try {
                    fin = new FileInputStream(source).getChannel();
                    fout= new FileOutputStream(target).getChannel();

                    // 使用transferto 进行文件处理
                    // transferTo一次最大只能复制2G, 因此，使用该方法也是建议在循环中进行处理，保证处理的完整性。
                    long size = fin.size();
                    long transferred = 0;
                    while (transferred < size) {
                        long num = fin.transferTo(transferred, size - transferred, fout);
                        transferred = transferred + num;
                    }

                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } finally {
                    if (fin!=null) {
                        fin.close();
                    }
                    if (fout!=null) {
                        fout.close();
                    }
                }
            }
        };
        fileCopy.copyFile(new File("F:\\1111.zip"), new File("F:\\11115.zip"));
    }
}